home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 April: Mac OS SDK / Dev.CD Apr 00 SDK1.toast / Development Kits / Mac OS / Open Transport 1.3 / Open Transport SDK / Open Tpt Module Developer / Samples / EchoModule.c next >
Encoding:
C/C++ Source or Header  |  1998-04-30  |  9.3 KB  |  377 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        EchoModule.c
  3.  
  4.     Contains:    Sample Stream Driver that echos data
  5.  
  6.         Sort of the minimal STREAMS driver - is neither TPI nor DLPI compliant
  7. */
  8.  
  9. #ifndef __OPENTPTMODULE__
  10. #include <OpenTptModule.h>
  11. #endif
  12. #ifndef _MPS_STROPTS_
  13. #include <stropts.h>
  14. #endif
  15.  
  16. /*
  17.  * Forward function declarations
  18.  */
  19.  
  20. int        echo_admin(void);
  21. int        echo_close(queue_t*, int, cred_t*);
  22. int        echo_open(queue_t*, dev_t*, int, int, cred_t*);
  23. int        echo_rsrv(queue_t*);
  24. int        echo_wput(queue_t*, mblk_t*);
  25.  
  26. /*
  27.  * Module information for the streamtab structure
  28.  */
  29.  
  30. static struct module_info minfo =  
  31. {
  32.     9000,                /* Module Number            */
  33.     "SmplEcho",            /* Name of module            */
  34.     0,                    /* Minimum data size        */
  35.     INFPSZ,                /* Maximum data size        */
  36.     2048,                /* Hi water mark for queue    */
  37.     128                    /* Lo water mark for queue    */
  38. };
  39.  
  40. /*
  41.  * Info for the "read" queue.
  42.  */
  43.  
  44. static struct qinit rinit = 
  45. {
  46.     putq,                /* Always "schedule" on the read_side            */
  47.     echo_rsrv,            /* Service routine for "incoming" data            */
  48.     echo_open,            /* Our open routine                                */
  49.     echo_close,         /* Our close routine                            */
  50.     echo_admin,            /* Our admin routine                            */
  51.     &minfo                /* Our module_info                                */
  52. };
  53.  
  54. /*
  55.  * Info for the "write" queue
  56.  */
  57.  
  58. static struct qinit winit =
  59. {
  60.     echo_wput,            /* Our write-side "put" routine                    */
  61.     0,                    /* No service routine on the write_side queue    */
  62.     0,                    /* open routine goes in read-side structure     */
  63.     0,                    /* close routine goes in read-side structure    */
  64.     0,                    /* admin routine goes in read-side structure    */
  65.     &minfo                /* Our module_info                                */
  66. };
  67.  
  68. /*
  69.  * The streamtab structure
  70.  */
  71.  
  72. static struct streamtab theStreamTab = 
  73. {
  74.     &rinit,            /* Our read-side qinit structure    */
  75.     &winit,            /* Our write-side qinit structure    */
  76.     0,                /* Not a mux - no structure info    */
  77.     0                /* Not a mux - no structure info    */
  78. };
  79.  
  80. static UInt8    gMinorNums[256];
  81.  
  82. /*******************************************************************************
  83. ** Open routine
  84. ********************************************************************************/
  85.  
  86. int echo_open(queue_t* rdq, dev_t* dev, int flag, int sflag, cred_t* creds)
  87. {
  88. #pragma unused (flag)
  89.     int        err;
  90.     size_t    idx;
  91.     /*
  92.      * Make sure caller is properly credentialed
  93.      */
  94.     if ( (err = drv_priv(creds)) != kOTNoError )
  95.         return err;
  96.     /*
  97.      * If we're being reopened - just return
  98.      */
  99.     if ( rdq->q_ptr != NULL )
  100.         return kOTNoError;
  101.     /*
  102.      * Make sure we're being opened properly - We only allow
  103.      * a "clone" open.
  104.      */
  105.     if ( sflag != CLONEOPEN )
  106.         return ENXIO;
  107.     /*
  108.      * Find a minor number we can use
  109.      */
  110.     for (idx = 0; idx < sizeof(gMinorNums); ++idx)
  111.         if ( gMinorNums[idx] == 0 )
  112.             break;
  113.     /*
  114.      * If we're out of minor numbers - return an error
  115.      */
  116.     if ( idx >= sizeof(gMinorNums) )
  117.         return ENXIO;
  118.     gMinorNums[idx] = 1;
  119.     /*
  120.      * Store our minor number in the q_ptr field (which is ours
  121.      * to do with as we please).  Normally, we would store some
  122.      * instance data there, but echo doesn't need any.
  123.      */
  124.     rdq->q_ptr = (void*)(idx + kFirstMinorNumber);
  125.     WR(rdq)->q_ptr    = rdq->q_ptr;
  126.     /*
  127.      * Set our device number so STREAMS knows what we are
  128.      */
  129.     *dev = makedev(getmajor(*dev), idx + kFirstMinorNumber);
  130.     /*
  131.      * return no error
  132.      */
  133.     return kOTNoError;
  134. }
  135.  
  136. /*******************************************************************************
  137. ** Close routine
  138. ********************************************************************************/
  139.  
  140. int echo_close(queue_t* rdq, int flags, cred_t* credP)
  141. {
  142.     /*
  143.      * Free my minor number.
  144.      * Zero out the q_ptr.  If we allocated any memory and stored
  145.      * it there, now would be a good time to free it!
  146.      */
  147.     gMinorNums[(UInt32)(rdq->q_ptr) - kFirstMinorNumber] = 0;
  148.     rdq->q_ptr        = NULL;
  149.     WR(rdq)->q_ptr    = NULL;
  150.     /*
  151.      * Return no error
  152.      */
  153.     return kOTNoError;
  154. }
  155.  
  156. /*******************************************************************************
  157. ** Admin routine
  158. **
  159. ** Admin routines are for future expansion - just return no error.
  160. ********************************************************************************/
  161.  
  162. int echo_admin()
  163. {
  164.     return kOTNoError;
  165. }
  166.  
  167. /*******************************************************************************
  168. ** Write-side put routine
  169. ********************************************************************************/
  170.  
  171. int echo_wput(queue_t* q, mblk_t* mp)
  172. {
  173.     /*
  174.      * Process the incoming message
  175.      */
  176.     switch (mp->b_datap->db_type)
  177.     {
  178.         /*
  179.          * These messages can't come from upstream
  180.          */
  181.         case M_COPYIN:
  182.         case M_COPYOUT:
  183.         case M_ERROR:
  184.         case M_HANGUP:
  185.         case M_IOCACK:
  186.         case M_IOCNAK:
  187.         case M_SETOPTS:
  188.         case M_SIG:
  189.             break;
  190.         /*
  191.          * Process a signal message - Under Open Transport, this is normally
  192.          * a timer message
  193.          */
  194.         case M_PCSIG:
  195.             break;
  196.         /*
  197.          * Undocumented message type
  198.          */
  199.         case M_HPDATA:
  200.             break;
  201.         /*
  202.          * You will get one of these if you use M_COPYIN.
  203.          */
  204.         case M_IOCDATA:
  205.             break;
  206.         /*
  207.          * These are messages for future expansion.  STREAMS says if you
  208.          * don't understand the message, free it if you are a driver.
  209.          */
  210.         case M_PCRSE:
  211.         case M_RSE:
  212.             break;
  213.             
  214.         /*
  215.          * Request to flush queues.  We're a driver, so we have to do a little
  216.          * more work than other modules when we receive one.
  217.          */
  218.         case M_FLUSH:
  219.             if ( mp->b_rptr[0] & FLUSHW)
  220.             {
  221.                 if ( (mp->b_rptr[0] & FLUSHBAND) && mp->b_wptr - mp->b_rptr == 2 )
  222.                     flushband(q, mp->b_rptr[1], FLUSHALL);
  223.                 else
  224.                     flushq(q, FLUSHALL);
  225.             }
  226.             if ( mp->b_rptr[0] & FLUSHR )
  227.             {
  228.                 if ( (mp->b_rptr[0] & FLUSHBAND) && mp->b_wptr - mp->b_rptr == 2 )
  229.                     flushband(RD(q), mp->b_rptr[1], FLUSHALL);
  230.                 else
  231.                     flushq(RD(q), FLUSHALL);
  232.                 mp->b_rptr[0] &= ~FLUSHW;
  233.                 qreply(q, mp);
  234.                 return 0;
  235.             }
  236.             break;
  237.             
  238.         /*
  239.          * These messages are rarely uses, but you may need to process them
  240.          */
  241.         case M_STOP:
  242.         case M_START:
  243.         case M_STOPI:
  244.         case M_STARTI:
  245.         case M_READ:
  246.         case M_BREAK:
  247.         case M_DELAY:
  248.         case M_CTL:
  249.             break;
  250.             
  251.         /*
  252.          * As a driver, it is our responsibility to NAK any IOCTL that we receive
  253.          * that we don't understand.  If we were a module, we would just pass it on.
  254.          */
  255.         case M_IOCTL:
  256.         {
  257.             struct iocblk* iocp = (struct iocblk*)mp->b_rptr;
  258.             iocp->ioc_error            = EINVAL;
  259.             iocp->ioc_count            = 0;
  260.             mp->b_datap->db_type    = M_IOCNAK;
  261.             qreply(q, mp);
  262.             return 0;
  263.         }
  264.         
  265.         /*
  266.          * We're an echo module, so just send the data back up the STREAM if we can.
  267.          * If we're flow controlled - put it on the queue for later processing.
  268.          */
  269.         case M_DATA:
  270.         case M_PROTO:
  271.         case M_PCPROTO:
  272.             /*
  273.              * If we are not flow controlled, or it is a hi-priority message,
  274.              * send it back up the read-side queue.
  275.              * Otherwise, do a putq on the read queue to schedule the
  276.              * data for being sent upstream when flow control lifts.
  277.              */
  278.             if ( mp->b_datap->db_type > QPCTL || bcanput(RD(q)->q_next, mp->b_band) )
  279.                 qreply(q, mp);
  280.             else
  281.                 putq(RD(q), mp);
  282.             return 0;
  283.             
  284.         /*
  285.          * Should never see one of these messages. It is an invisible message
  286.          * used by the streamhead.
  287.          */
  288.         case M_PASSFP:
  289.             break;
  290.             
  291.         default:
  292.             break;
  293.     }
  294.     freemsg(mp);
  295.     return 0;
  296. }
  297.  
  298. /*******************************************************************************
  299. ** Read-side service routine
  300. **
  301. ** Data to be sent upstream was put on the read-side queue, if flow control
  302. ** was on.  When flow control is lifted, this routine will be scheduled to run.
  303. ********************************************************************************/
  304.  
  305. int echo_rsrv(queue_t* q)
  306. {
  307.     mblk_t*    mp;
  308.     /*
  309.      * We know that only M_PROTO and M_DATA messages are on the queue, since that
  310.      * is all that we scheduled.
  311.      */
  312.     while ( (mp = getq(q)) != NULL )
  313.     {
  314.         /*
  315.          * If we're flow controlled, get out and we'll come back when the flow-
  316.          * control lifts.
  317.          */
  318.         if ( !bcanput(q->q_next, mp->b_band) )
  319.         {
  320.             putbq(q, mp);
  321.             return 0;
  322.         }
  323.         /*
  324.          * Otherwise, send the data upstream, and get some more
  325.          */
  326.         putnext(q, mp);
  327.     }
  328. }
  329.  
  330.  
  331. /* ------------------------------------------------------------------------
  332.  
  333.     THESE FUNCTIONS AND DATA STRUCTURES ARE SPECIFIC TO THE MACINTOSH IMPLEMENTATION
  334.     OF STREAMS. THESE ROUTINES WOULD NOT EXIST IN OTHER STREAMS ENVIRONMENTS.
  335.     
  336.     WHEN PORTING OTHER STREAMS CODE TO THE MACINTOSH, THESE ROUTINES AND DATA
  337.     STRUCTURES MUST BE ADDED.
  338.  
  339.    ------------------------------------------------------------------------ */
  340.  
  341. /*******************************************************************************
  342. ** install_info structure, and the GetInstallInfo function
  343. **
  344. ** This is the structure that tells Open Transport about your module. OT calls
  345. ** your "GetInstallInfo" function to get this information.
  346. **
  347. ********************************************************************************/
  348.  
  349. static struct install_info theInstallInfo =
  350. {
  351.     &theStreamTab,            // Stream Tab pointer
  352.     kOTModIsDriver,            // Tell OT we are a driver
  353.     SQLVL_MODULE,            // Synchronization level - the module will never
  354.                             // be re-entered with this setting
  355.     0,                        // Shared writer list buddy
  356.     0,                        // Open Transport use - always set to 0
  357.     0                        // Flag - always set to 0
  358. };
  359.     
  360. install_info* GetOTInstallInfo()
  361. {
  362.     return &theInstallInfo;
  363. }
  364.  
  365. /*******************************************************************************
  366. ** This is the function that will be called the first time that this code
  367. ** is loaded.  It is guaranteed that this function is call at SystemTask time
  368. ** on the Macintosh.
  369. ********************************************************************************/
  370.  
  371. Boolean InitStreamModule(void* cookie)
  372. {
  373.     BZERO(gMinorNums, sizeof(gMinorNums));
  374.     return true;
  375. }
  376.  
  377.